import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @author hht
 * @ClassName OptionalTester  初衷通过包装类简化Null的处理，个人感觉简化代码 和 lambda结合，
 * 但缺点在团队和个人不熟悉的时候大大降低代码可读性
 * 代码 引用自 https://blog.csdn.net/zknxx/article/details/78586799
 * @Description TODO
 * @Date 2019/2/19 14:21
 * @VERSION 1.0
 */
public class OptionalTester {
    public static void main(String[] args) {
//        testOf();
//        testOrElse();
//        testOrElseGet();
        test();
    }
    private static void test(){
        User user = new User();
        Role role = new Role();
//        role.setRoleName("测试");
//        user.setRole(role);
        String roleName = Optional.ofNullable(user).map(User::getRole).map(Role::getRoleName).orElse("hht");
        System.out.println(roleName);

    }
    private static  void testOf(){
        Optional<String> stringOptional = Optional.of("张三");
        System.out.println(stringOptional.get());
    }
    private static void testOrElse(){
        Optional<String> stringOptional = Optional.of("张三");
        System.out.println(stringOptional.orElse("zhangsan"));

        Optional<String> emptyOptional = Optional.empty();
        System.out.println(emptyOptional.orElse("李四"));
    }
    private static void testOrElseGet(){
        Optional<String> stringOptional = Optional.of("张三");
        System.out.println(stringOptional.orElseGet(() -> "zhangsan"));

        Optional<String> emptyOptional = Optional.empty();
        System.out.println(emptyOptional.orElseGet(() -> "orElseGet"));

    }

    /**
     * 如果创建的Optional中有值存在，则返回此值，否则抛出一个由指定的Supplier接口生成的异常
     */
    private static void testOrElseThrow(){
        Optional<String> stringOptional = Optional.of("张三");
        System.out.println(stringOptional.orElseGet(() -> "zhangsan"));

        Optional<String> emptyOptional = Optional.empty();
        System.out.println(emptyOptional.orElseGet(() -> "orElseGet"));

    }
    /**
     * 如果创建的Optional中的值满足filter中的条件，则返回包含该值的Optional对象，否则返回一个空的Optional对象
     * 注意Optional中的filter方法和Stream中的filter方法是有点不一样的，Stream中的filter方法是对一堆元素进
     * 行过滤，而Optional中的filter方法只是对一个元素进行过滤，可以把Optional看成是最多只包含一个元素
     * 的Stream。
     */
    private static void testFilter(){
        Optional<String> stringOptional = Optional.of("zhangsan");
        System.out.println(stringOptional.filter(e -> e.length() > 5).orElse("王五"));
        stringOptional = Optional.empty();
        System.out.println(stringOptional.filter(e -> e.length() > 5).orElse("lisi"));

    }
    /**
     * 如果创建的Optional中的值存在，对该值执行提供的Function函数调用
     */
    private static void testMap(){
        //map方法执行传入的lambda表达式参数对Optional实例的值进行修改,修改后的返回值仍然是一个Optional对象
        Optional<String> stringOptional = Optional.of("zhangsan");
        System.out.println(stringOptional.map(e -> e.toUpperCase()).orElse("失败"));

        stringOptional = Optional.empty();
        System.out.println(stringOptional.map(e -> e.toUpperCase()).orElse("失败"));
    }
    /**
     * 如果创建的Optional中的值存在，就对该值执行提供的Function函数调用，返回一个Optional类型的值，否
     * 则就返回一个空的Optional对象.flatMap与map（Funtion）方法类似，区别在于flatMap中的mapper返回
     * 值必须是Optional，map方法的mapping函数返回值可以是任何类型T。调用结束时，flatMap不会对结果
     * 用Optional封装。
     */
    private static void testFlatMap(){
        Optional<String> stringOptional = Optional.of("zhangsan");
        System.out.println(stringOptional.filter(e -> e.length() > 5).orElse("王五"));
        stringOptional = Optional.empty();
        System.out.println(stringOptional.filter(e -> e.length() > 5).orElse("lisi"));

    }
    /**
     * ifPresent方法的参数是一个Consumer的实现类，
     * Consumer类包含一个抽象方法，该抽象方法对传入的值进行处理，只处理没有返回值。
     */
    private static void ifPresent(){
        Optional<String> stringOptional = Optional.of("zhangsan");
        stringOptional.ifPresent(e-> System.out.println("我被处理了。。。"+e));
    }

}

class User{
    private Role role;

    public Role getRole() {
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }
}
class Role{
    private String roleName ;

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }
}
